import 'dart:developer';
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter_practice/src/seat/seat_view.dart';
import 'package:photo_view/photo_view.dart';
import 'dart:math' as math;

class FineSeatView extends StatefulWidget {
  const FineSeatView({
    super.key,
    this.rows = 10,
    this.columns = 20,
    this.minScale = 0.8,
    this.maxScale = 2.5,
    required this.seatsState,
    required this.selectedIcon,
    required this.unSelectedIcon,
    required this.soldIcon,
    required this.disabledIcon,
    this.size = 18,
    this.onChanged,
  });

  final int rows; //行数
  final int columns; //列数
  final double minScale; //最小放大比例
  final double maxScale; //最大放大比例
  final List<List<SeatState>> seatsState;
  final double size;
  final String selectedIcon;
  final String unSelectedIcon;
  final String soldIcon;
  final String disabledIcon;
  final OnSeatStateChanged? onChanged;

  @override
  State<FineSeatView> createState() => _FineSeatViewState();
}

class _FineSeatViewState extends State<FineSeatView> {
  final double kSeatMaxSize = 32;
  final int kDisplayColumns = 12;
  PhotoViewController photoViewController = PhotoViewController();
  final SeatIndexBarController barController = SeatIndexBarController(1);

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addPostFrameCallback((_) {
      if (widget.columns <= kDisplayColumns) return;
      log('customSize=$customSize  childSize=$childSize  ${photoViewController.value}');

      final scaleBoundaries = ScaleBoundaries(
          PhotoViewComputedScale.contained,
          PhotoViewComputedScale.covered,
          PhotoViewComputedScale.contained,
          customSize,
          childSize);
      minScale = scaleBoundaries.minScale;
      maxScale = scaleBoundaries.maxScale;

      double expectWidth = itemSize * kDisplayColumns;
      if (childSize.width > expectWidth) {
        double widthScale = childSize.width / expectWidth;
        double scale = math.min(widthScale, maxScale);

        photoViewController.scale = scale;
        barController.value = scale;
        setState(() {});
      }
    });
  }

  Size customSize = Size.zero;
  Size childSize = Size.zero;
  double minScale = 1.0;
  double maxScale = 1.0;
  double itemSize = 32;

  @override
  Widget build(BuildContext context) {
    int rows = widget.rows;
    int columns = widget.columns;

    return LayoutBuilder(builder: (context, constraints) {
      final double itemWidth = constraints.maxWidth / columns;
      final double itemHeight = constraints.maxHeight / rows;
      itemSize = itemWidth < itemHeight ? itemWidth : itemHeight;

      log("屏幕宽=${constraints.maxWidth} 屏幕高=${constraints.maxHeight} 座位大小=$itemSize");
      log("view宽=${itemSize * columns} view高=${itemSize * rows} ");

      return Stack(
        children: [
          PhotoView.customChild(
              controller: photoViewController,
              backgroundDecoration: const BoxDecoration(color: Colors.white),
              initialScale: PhotoViewComputedScale.contained,
              minScale: PhotoViewComputedScale.contained,
              maxScale: PhotoViewComputedScale.covered,
              customSize: customSize =
                  Size(constraints.maxWidth, constraints.maxHeight),
              childSize: childSize = Size(itemSize * columns, itemSize * rows),
              basePosition: Alignment.topLeft,
              onScaleEnd: (BuildContext context, ScaleEndDetails details,
                  PhotoViewControllerValue value) {
                log('onScaleEnd === >>$value ');
                double? scale;
                if (value.scale == null) return;

                if (value.scale! > maxScale) {
                  scale = maxScale;
                } else if (value.scale! < minScale) {
                  scale = minScale;
                } else {
                  scale = value.scale;
                }
                print('onScaleEnd==>> ${scale}');
                if (scale != null) {
                  barController.value = scale ?? 1;
                  setState(() {});
                }
              },
              child: Column(
                children: List.generate(rows, (rowIndex) {
                  return Row(
                    children: List.generate(columns, (colIndex) {
                      return SeatItemWidget(
                        rowIndex: rowIndex,
                        colIndex: colIndex,
                        size: itemSize,
                        state: getState(rowIndex, colIndex),
                        selectedIcon: widget.selectedIcon,
                        unSelectedIcon: widget.unSelectedIcon,
                        soldIcon: widget.soldIcon,
                        disabledIcon: widget.disabledIcon,
                        onChanged: widget.onChanged,
                      );
                    }),
                  );
                }),
              )),
          Align(
            alignment: Alignment.topLeft,
            child: SeatIndexBar(
              controller: barController,
              rows: rows,
              size: itemSize,
            ),
          ),
        ],
      );
    });
  }

  SeatState getState(int rowIndex, int colIndex) {
    if (widget.seatsState.length > rowIndex &&
        widget.seatsState[rowIndex].length > colIndex) {
      return widget.seatsState[rowIndex][colIndex];
    }
    return SeatState.empty;
  }
}

/// Internal class to wraps custom scale boundaries (min, max and initial)
/// Also, stores values regarding the two sizes: the container and teh child.
class ScaleBoundaries {
  const ScaleBoundaries(
    this._minScale,
    this._maxScale,
    this._initialScale,
    this.outerSize,
    this.childSize,
  );

  final dynamic _minScale;
  final dynamic _maxScale;
  final dynamic _initialScale;
  final Size outerSize;
  final Size childSize;

  double get minScale {
    assert(_minScale is double || _minScale is PhotoViewComputedScale);
    if (_minScale == PhotoViewComputedScale.contained) {
      return _scaleForContained(outerSize, childSize) *
          (_minScale as PhotoViewComputedScale).multiplier; // ignore: avoid_as
    }
    if (_minScale == PhotoViewComputedScale.covered) {
      return _scaleForCovering(outerSize, childSize) *
          (_minScale as PhotoViewComputedScale).multiplier; // ignore: avoid_as
    }
    assert(_minScale >= 0.0);
    return _minScale;
  }

  double get maxScale {
    assert(_maxScale is double || _maxScale is PhotoViewComputedScale);
    if (_maxScale == PhotoViewComputedScale.contained) {
      return (_scaleForContained(outerSize, childSize) *
              (_maxScale as PhotoViewComputedScale) // ignore: avoid_as
                  .multiplier)
          .clamp(minScale, double.infinity);
    }
    if (_maxScale == PhotoViewComputedScale.covered) {
      return (_scaleForCovering(outerSize, childSize) *
              (_maxScale as PhotoViewComputedScale) // ignore: avoid_as
                  .multiplier)
          .clamp(minScale, double.infinity);
    }
    return _maxScale.clamp(minScale, double.infinity);
  }

  double get initialScale {
    assert(_initialScale is double || _initialScale is PhotoViewComputedScale);
    if (_initialScale == PhotoViewComputedScale.contained) {
      return _scaleForContained(outerSize, childSize) *
          (_initialScale as PhotoViewComputedScale) // ignore: avoid_as
              .multiplier;
    }
    if (_initialScale == PhotoViewComputedScale.covered) {
      return _scaleForCovering(outerSize, childSize) *
          (_initialScale as PhotoViewComputedScale) // ignore: avoid_as
              .multiplier;
    }
    return _initialScale.clamp(minScale, maxScale);
  }

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is ScaleBoundaries &&
          runtimeType == other.runtimeType &&
          _minScale == other._minScale &&
          _maxScale == other._maxScale &&
          _initialScale == other._initialScale &&
          outerSize == other.outerSize &&
          childSize == other.childSize;

  @override
  int get hashCode =>
      _minScale.hashCode ^
      _maxScale.hashCode ^
      _initialScale.hashCode ^
      outerSize.hashCode ^
      childSize.hashCode;
}

double _scaleForContained(Size size, Size childSize) {
  final double imageWidth = childSize.width;
  final double imageHeight = childSize.height;

  final double screenWidth = size.width;
  final double screenHeight = size.height;

  return math.min(screenWidth / imageWidth, screenHeight / imageHeight);
}

double _scaleForCovering(Size size, Size childSize) {
  final double imageWidth = childSize.width;
  final double imageHeight = childSize.height;

  final double screenWidth = size.width;
  final double screenHeight = size.height;

  return math.max(screenWidth / imageWidth, screenHeight / imageHeight);
}

double _clampSize(double size, ScaleBoundaries scaleBoundaries) {
  return size.clamp(scaleBoundaries.minScale, scaleBoundaries.maxScale);
}
